package com.franklin.java.api.dom;

import com.franklin.java.dom.livetemplate.model.TemplateSet;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * @author Franklin
 * @since 2021/8/4 15:48
 */
public class XmlUtils {

    public static <E> E parseObject(String fileName, Class<E> typeClass) {
        try {
            return parseObject(new FileInputStream(fileName),typeClass);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <E> E parseObject(InputStream inputStream, Class<E> typeClass) {
        try {
            SAXBuilder saxBuilder = new SAXBuilder();
            Document document = saxBuilder.build(inputStream);
            Element element = document.getRootElement();
            return (E) resolve(element,typeClass);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Object resolve(Element element, Class<?> typeClass)
        throws NoSuchMethodException,
        IllegalAccessException,
        InvocationTargetException,
        InstantiationException
    {
        Field[] declaredFields = typeClass.getDeclaredFields();
        Object object = typeClass.getDeclaredConstructor().newInstance();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            Object value = null;
            XmlSub xmlSub = declaredField.getDeclaredAnnotation(XmlSub.class);
            String fieldName = declaredField.getName();
            if (Objects.nonNull(xmlSub)) {
                //子xml
                Class<?> fieldType = declaredField.getType();
                if (Collection.class.isAssignableFrom(fieldType)){
                    //集合
                    String subName = xmlSub.name();
                    if ("".equals(subName)){
                        String simpleName = xmlSub.value().getSimpleName();
                        subName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
                    }

                    List<Element> children = element.getChildren(subName);
                    List<Object> subList = new ArrayList<>();
                    for (Element child : children) {
                        subList.add(resolve(child,xmlSub.value()));
                    }
                    value = subList;
                }else {
                    //单个
                    Element child = element.getChild(fieldName);
                    value = resolve(child,xmlSub.value());
                }
            }
            XmlAttribute xmlAttribute = declaredField.getDeclaredAnnotation(XmlAttribute.class);
            if (Objects.nonNull(xmlAttribute)) {
                //属性
                String attributeName = "".equals(xmlAttribute.value()) ? fieldName : xmlAttribute.value();
                value = element.getAttributeValue(attributeName);
            }
            //判断是不是value
            if (fieldName.equals("value")) {
                value = element.getValue();
            }
            declaredField.set(object,value);
        }
        return object;
    }
}
